package top.codedance.iotp.server.net.handle;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import top.codedance.iotp.common.constent.Command;
import top.codedance.iotp.common.entity.CommonEntity;
import top.codedance.iotp.common.util.JsonUtil;
import top.codedance.iotp.manage.client.cmdentity.*;
import top.codedance.iotp.server.ServerApplication;
import top.codedance.iotp.server.net.TcpServer;
import top.codedance.iotp.server.net.handle.configuration.ClientHandlerConfig;
import top.codedance.iotp.server.net.session.Session;
import com.beust.jcommander.JCommander;
import cd.io.netty.channel.Channel;
import cd.io.netty.channel.ChannelHandlerContext;
import cd.io.netty.channel.SimpleChannelInboundHandler;
import org.apache.log4j.Logger;

import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static top.codedance.iotp.manage.client.configration.Command.*;

public class ConsoleReceptionHandler extends SimpleChannelInboundHandler<CommonEntity> {
    private static Logger logger = ServerApplication.getLogger(ConsoleReceptionHandler.class);

    protected void messageReceived(ChannelHandlerContext channelHandlerContext, CommonEntity commonEntity) throws Exception {
        try {
            if (ClientHandlerConfig.consoleCmds.contains(commonEntity.getCommand())) {
                logger.debug("CONSOLE_MANAGE_COMMAND: " + commonEntity.getCommand());
                String ip = channelHandlerContext.channel().remoteAddress().toString();
                logger.debug("ip: " + ip);
                JCommander jCommander;
                if (ip.indexOf("127.0.0.1") != -1) {
                    String task = new String(commonEntity.getBody(), StandardCharsets.UTF_8);
                    String[] cmdSplits = task.split("\\s+");
                    String cmd = cmdSplits[0].toLowerCase();
                    if (cmd.equals(SHUTDOWN)) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(new Date());
                        calendar.add(Calendar.SECOND, 10);
                        ServerApplication.timer.schedule(new TimerTask() {
                            @Override
                            public void run() {
                                logger.debug("user shutdown.");
                                System.exit(0);
                            }
                        }, calendar.getTime());
                        send(channelHandlerContext, "Server will shutdown in 10 seconds.");
                    } else if (cmd.equals(REFRESH_USERS_CACHE)) {
                        ServerApplication.initUsersCache();
                        send(channelHandlerContext, "Refresh users cache success.");
                    } else if (cmd.equals(VIEW_USERS_CACHE)) {
                        JSONArray o = (JSONArray) JSON.toJSON(ServerApplication.users);
                        send(channelHandlerContext, JsonUtil.getInstance().format(o.toJSONString()));
                    } else if (cmd.equals(REFRESH_DEVICIES_CACHE)) {
                        ServerApplication.initDeviciesCache();
                        send(channelHandlerContext, "Refresh devicies cache success.");
                    } else if (cmd.equals(VIEW_DEVICIES_CACHE)) {
                        JSONArray o = (JSONArray) JSON.toJSON(ServerApplication.devicies);
                        send(channelHandlerContext, JsonUtil.getInstance().format(o.toJSONString()));
                    } else if (cmd.equals(VIEW_ONLINE_DEVICIES)) {
                        ViewDeviciesCacheCli viewDeviciesCacheCli = new ViewDeviciesCacheCli();
                        jCommander = JCommander.newBuilder().addObject(viewDeviciesCacheCli).build();
                        jCommander.parse(cmdSplits);
                        JSONArray o;
                        if(viewDeviciesCacheCli.getDisplayType().equals(ViewDeviciesCacheCli.DisplayType.CONSOLE)){
                            o = new JSONArray();
                            for (String di : TcpServer.sessionManager.getClientDeviceIds()){
                                if(di.matches("^Console\\[\\d+\\]::.*")){
                                    o.add(di);
                                }
                            }
                        } else if(viewDeviciesCacheCli.getDisplayType().equals(ViewDeviciesCacheCli.DisplayType.CLIENT)){
                            o = new JSONArray();
                            for (String di : TcpServer.sessionManager.getClientDeviceIds()){
                                if(!di.matches("^Console\\[\\d+\\]::.*") && !di.matches("^Manage::.*")){
                                    o.add(di);
                                }
                            }
                        } else if(viewDeviciesCacheCli.getDisplayType().equals(ViewDeviciesCacheCli.DisplayType.CLIENT_MANAGE)){
                            o = new JSONArray();
                            for (String di : TcpServer.sessionManager.getClientDeviceIds()){
                                if(di.matches("^Manage::.*")){
                                    o.add(di);
                                }
                            }
                        } else{
                            o = (JSONArray) JSON.toJSON(TcpServer.sessionManager.getClientDeviceIds());
                        }
                        send(channelHandlerContext, JsonUtil.getInstance().format(o.toJSONString()));
                    } else if (cmd.equals(VIEW_INFOMATION)) {
                        JSONObject o = ServerApplication.getServerInfomation();
                        send(channelHandlerContext, JsonUtil.getInstance().format(o.toJSONString()));
                    } else if (cmd.equals(GET_TCP_COUNT)) {
                        send(channelHandlerContext, String.valueOf(ServerApplication.tcpConnectCounter.get()));
                    } else if (cmd.equals(GET_HTTP_COUNT)) {
                        send(channelHandlerContext, String.valueOf(ServerApplication.httpConnectCounter.get()));
                    } else if (cmd.equals(GET_WS_COUNT)) {
                        send(channelHandlerContext, String.valueOf(ServerApplication.wsConnectCounter.get()));
                    } else if (cmd.equals(IS_SAFY_MODE)) {
                        send(channelHandlerContext, String.valueOf(ServerApplication.isSafyMode));
                    } else if (cmd.equals(ENABLE_SAFY_MODE)) {
                        ServerApplication.isSafyMode = true;
                        send(channelHandlerContext, String.valueOf(ServerApplication.isSafyMode));
                    } else if (cmd.equals(DISABLE_SAFY_MODE)) {
                        ServerApplication.isSafyMode = false;
                        send(channelHandlerContext, String.valueOf(ServerApplication.isSafyMode));
                    } else if (cmd.equals(VIEW_BLACK_LIST)) {
                        JSONArray o = (JSONArray) JSON.toJSON(ServerApplication.blacklist);
                        send(channelHandlerContext, JsonUtil.getInstance().format(o.toJSONString()));
                    } else if (cmd.equals(ADD_CLIENT_TO_BLACK)) {
                        AddClientToBlackCli addClientToBlackCli = new AddClientToBlackCli();
                        jCommander = JCommander.newBuilder().addObject(addClientToBlackCli).build();
                        jCommander.parse(cmdSplits);
                        if (addClientToBlackCli.getDynamicParams().size() > 0) {
                            for(String id : addClientToBlackCli.getDynamicParams()) {
                                if (!ServerApplication.blacklist.contains(id)) {
                                    ServerApplication.blacklist.add(id);
                                }
                                send(channelHandlerContext, "Add " + id + " success.");
                            }
                        } else {
                            send(channelHandlerContext, "Please input device id.");
                        }
                    } else if (cmd.equals(DEL_CLIENT_TO_BLACK)) {
                        DelClientTBlackCli delClientTBlackCli = new DelClientTBlackCli();
                        jCommander = JCommander.newBuilder().addObject(delClientTBlackCli).build();
                        jCommander.parse(cmdSplits);
                        if (delClientTBlackCli.getDynamicParams().size() > 0) {
                            for (String id : delClientTBlackCli.getDynamicParams()) {
                                if (ServerApplication.blacklist.contains(id)) {
                                    ServerApplication.blacklist.remove(id);
                                }
                                send(channelHandlerContext, "Delete " + id + " success.");
                            }
                        } else {
                            send(channelHandlerContext, "Please input device id.");
                        }
                    } else if (cmd.equals(KILL_CLIENT)) {
                        KillClientCli killClientCli = new KillClientCli();
                        jCommander = JCommander.newBuilder().addObject(killClientCli).build();
                        jCommander.parse(cmdSplits);
                        if (killClientCli.getDynamicParams().size() > 0) {
                            Session session;
                            Channel channel;
                            for (String id : killClientCli.getDynamicParams()) {
                                try {
                                    session = TcpServer.sessionManager.getSessionByDeviceId(id);
                                    channel = session.getChannel();
                                    channel.close();
                                    TcpServer.sessionManager.offLine(channel, channel.id().toString());
                                    send(channelHandlerContext, "Kill " + id + " success");
                                }catch(Exception ex){
                                    send(channelHandlerContext, "Kill " + id + " fail");
                                }
                            }
                        } else {
                            send(channelHandlerContext, "Please input device id.");
                        }
                    } else if (cmd.equals(SHUTDOWN_CLIENT)) {
                        ShutdownClientCli shutdownClientCli = new ShutdownClientCli();
                        jCommander = JCommander.newBuilder().addObject(shutdownClientCli).build();
                        jCommander.parse(cmdSplits);
                        if (shutdownClientCli.getDynamicParams().size() > 0) {
                            Session session;
                            String s;
                            for (String id : shutdownClientCli.getDynamicParams()) {
                                try {
                                    session = TcpServer.sessionManager.getSessionByDeviceId(id);
                                    CommonEntity commonEntity2 = new CommonEntity(ServerApplication.getDataVersion());
                                    commonEntity2.setCommand(Command.SHUTDOWN);
                                    JSONObject b = new JSONObject();
                                    b.put("isExceptionExit", shutdownClientCli.getExceptionExit());
                                    b.put("amount", shutdownClientCli.getAmount());
                                    commonEntity2.setBody(b.toJSONString().getBytes(StandardCharsets.UTF_8));
                                    CommonEntity commonEntity3 = TcpServer.syncRequestService.sendSyncMsg(session.getChannel(), commonEntity2);
                                    s = new String(commonEntity3.getBody());
                                    send(channelHandlerContext, "[" + id + "] : " + s);
                                }catch(Exception ex){
                                    send(channelHandlerContext, "Shutdown " + id + " fail");
                                }
                            }
                        } else {
                            send(channelHandlerContext, "Please input device id.");
                        }
                    } else if (cmd.equals(REGISTY_SERVER)) {
                        ServerApplication.registryExecutor.registy();
                        send(channelHandlerContext, "Registy success.");
                    } else if (cmd.equals(VIEW_SERVER_VERSION)) {
                        send(channelHandlerContext, ServerApplication.version.toString());
                    } else if (cmd.equals(UPDATE_CLIENT_VERSION)) {
                        BaseCli bc = new BaseCli();
                        jCommander = JCommander.newBuilder().addObject(bc).build();
                        jCommander.parse(cmdSplits);
                        List<String> dynamicParams = bc.getDynamicParams();
                        if (dynamicParams != null && dynamicParams.size() > 0){
                            Long versionCode = Long.valueOf(dynamicParams.get(0));
                            ServerApplication.versionFileUtil.update(versionCode.toString());
                            ServerApplication.setLastClientVersionCode(versionCode);
                            send(channelHandlerContext, "Update success.");
                        }else{
                            send(channelHandlerContext, "Update fail.");
                        }
                    } else if (cmd.equals(SET_CLIENT_UPGRADE_REPOSITORY)) {
                        BaseCli bc = new BaseCli();
                        jCommander = JCommander.newBuilder().addObject(bc).build();
                        jCommander.parse(cmdSplits);
                        List<String> dynamicParams = bc.getDynamicParams();
                        if (dynamicParams != null && dynamicParams.size() > 0){
                            String regex = "(((https|http)?://)?([a-z0-9]+[.])|(www.))"
                                    + "\\w+[.|\\/]([a-z0-9]{0,})?[[.]([a-z0-9]{0,})]+((/[\\S&&[^,;\u4E00-\u9FA5]]+)+)?([.][a-z0-9]{0,}+|/?)";//设置正则表达式
                            Pattern pat = Pattern.compile(regex.trim());//比对
                            Matcher mat = pat.matcher(dynamicParams.get(0).trim());
                            if(mat.matches()) {
                                ServerApplication.clientUpgradeReposity = dynamicParams.get(0);
                                send(channelHandlerContext, "Update success.");
                            }else{
                                send(channelHandlerContext, "Update fail.");
                            }
                        }else{
                            send(channelHandlerContext, "Update fail.");
                        }
                    } else if (cmd.equals(VIEW_CLIENT_UPGRADE_REPOSITORY)) {
                        send(channelHandlerContext, ServerApplication.clientUpgradeReposity);
                    } else {
                        send(channelHandlerContext, "Not find command : " + task);
                    }
                }
            } else {
                channelHandlerContext.fireChannelRead(commonEntity); //向后传递
            }
        }catch (Exception e){
            logger.debug(e.getMessage());
            send(channelHandlerContext, "Server Exception, Please contact the administrator.");
        }
    }

    private void send(ChannelHandlerContext channelHandlerContext, String data) throws Exception {
        CommonEntity commonEntity2 = new CommonEntity();
        commonEntity2.setCommand(Command.CONSOLE_MANAGE_COMMAND_RECEIVE);
        commonEntity2.setBody(data.getBytes(StandardCharsets.UTF_8));
        channelHandlerContext.writeAndFlush(commonEntity2);
    }
}
